<!--
  功能：功能描述
  时间：2025年06月19日 15:37:05
-->
<template>
  <div class="large-screen-bg">
    <div class="bg-animate">
      <div class="glow-top"></div>
      <div class="glow-bottom"></div>
      <div class="glow-left"></div>
      <div class="glow-right"></div>
      <div class="stars">
        <span v-for="n in 16" :key="n" class="star" :style="starStyle(n)"></span>
      </div>
    </div>
    <div ref="scaleRef" class="scale-wrapper">
      <div class="large-screen-container">
        <div class="side-panel left-panel">
          <div class="panel-title">数据看板</div>
          <div class="data-card highlight-card">
            <div class="card-label">今日访问量</div>
            <div class="card-value">{{ todayVisits }}</div>
            <div class="card-sub">同比增长 <span class="up">+12.5%</span></div>
          </div>
          <div class="data-card">
            <div class="card-label">活跃用户</div>
            <div class="card-value">{{ activeUsers }}</div>
            <div class="progress-ring">
              <svg width="60" height="60">
                <circle cx="30" cy="30" r="26" stroke="#1de9b6" stroke-width="6" fill="none"/>
                <circle cx="30" cy="30" r="26" stroke="#2979ff" stroke-width="6" fill="none"
                  :stroke-dasharray="2 * Math.PI * 26"
                  :stroke-dashoffset="(1 - activeRate) * 2 * Math.PI * 26"
                  stroke-linecap="round"
                  style="transition:stroke-dashoffset 1s"/>
              </svg>
              <span class="progress-text">{{ Math.round(activeRate * 100) }}%</span>
            </div>
          </div>
          <div class="data-card">
            <div class="card-label">地区分布</div>
            <div class="mini-bar">
              <div v-for="item in regionData" :key="item.name" class="mini-bar-item">
                <span class="mini-bar-label">{{ item.name }}</span>
                <div class="mini-bar-bar" :style="{width: item.value + '%', background: item.color}"></div>
                <span class="mini-bar-value">{{ item.value }}</span>
              </div>
            </div>
          </div>
        </div>
        <div class="center-panel">
          <div class="main-title">
            <img src="/favicon.ico" class="logo" />
            中国数据大屏
            <div class="subtitle">Data Visualization Dashboard</div>
            <div class="time">{{ nowTime }}</div>
          </div>
          <div ref="mapRef" class="map-container"></div>
        </div>
        <div class="side-panel right-panel">
          <div class="panel-title">统计分析</div>
          <div class="data-card highlight-card">
            <div class="card-label">本月营收</div>
            <div class="card-value">¥{{ monthIncome }}</div>
            <div class="card-sub">环比增长 <span class="up">+8.2%</span></div>
          </div>
          <div class="data-card">
            <div class="card-label">订单趋势</div>
            <div class="mini-bar">
              <div v-for="item in orderTrend" :key="item.day" class="mini-bar-item">
                <span class="mini-bar-label">{{ item.day }}</span>
                <div class="mini-bar-bar" :style="{width: item.value + '%', background: '#ffb300'}"></div>
                <span class="mini-bar-value">{{ item.value }}</span>
              </div>
            </div>
          </div>
          <div class="data-card">
            <div class="card-label">在线设备</div>
            <div class="card-value">{{ onlineDevices }}</div>
            <div class="progress-ring">
              <svg width="60" height="60">
                <circle cx="30" cy="30" r="26" stroke="#ff1744" stroke-width="6" fill="none"/>
                <circle cx="30" cy="30" r="26" stroke="#ffd600" stroke-width="6" fill="none"
                  :stroke-dasharray="2 * Math.PI * 26"
                  :stroke-dashoffset="(1 - deviceRate) * 2 * Math.PI * 26"
                  stroke-linecap="round"
                  style="transition:stroke-dashoffset 1s"/>
              </svg>
              <span class="progress-text">{{ Math.round(deviceRate * 100) }}%</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick, watch, reactive } from 'vue';
import * as echarts from 'echarts';
// @ts-ignore
import chinaMap from '@/assets/china.json';

const mapRef = ref<HTMLDivElement | null>(null);
const scaleRef = ref<HTMLDivElement | null>(null);
let myChart: echarts.ECharts | null = null;

const DESIGN_WIDTH = 1920;
const DESIGN_HEIGHT = 1080;

function setScale() {
  if (!scaleRef.value) return;
  const ww = window.innerWidth;
  const wh = window.innerHeight;
  const scale = Math.min(ww / DESIGN_WIDTH, wh / DESIGN_HEIGHT);
  scaleRef.value.style.transform = `scale(${scale}) translate(-50%, -50%)`;
  scaleRef.value.style.left = '50%';
  scaleRef.value.style.top = '50%';
  scaleRef.value.style.position = 'absolute';
  scaleRef.value.style.transformOrigin = 'left top';
  scaleRef.value.style.width = DESIGN_WIDTH + 'px';
  scaleRef.value.style.height = DESIGN_HEIGHT + 'px';
  if (myChart) myChart.resize();
}

function resizeChart() {
  if (myChart) {
    myChart.resize();
  }
}

// 动态数据
const todayVisits = ref(0);
const todayVisitsTarget = 12345;
const activeUsers = ref(0);
const activeUsersTarget = 2345;
const activeRate = ref(0.72);
const regionData = ref([
  { name: '华北', value: 80, color: '#00eaff' },
  { name: '华东', value: 65, color: '#ff6b81' },
  { name: '华南', value: 50, color: '#ffd600' },
  { name: '西南', value: 35, color: '#1de9b6' }
]);
const monthIncome = ref(0);
const monthIncomeTarget = 987654;
const orderTrend = ref([
  { day: '周一', value: 30 },
  { day: '周二', value: 50 },
  { day: '周三', value: 80 },
  { day: '周四', value: 60 },
  { day: '周五', value: 90 },
  { day: '周六', value: 70 },
  { day: '周日', value: 40 }
]);
const onlineDevices = ref(0);
const onlineDevicesTarget = 128;
const deviceRate = ref(0.86);
const nowTime = ref('');

// 地图数据响应式
const mapData = reactive([
  { name: '北京', value: 200 },
  { name: '上海', value: 300 },
  { name: '广东', value: 800 },
  { name: '四川', value: 500 }
]);

function updateTime() {
  const d = new Date();
  nowTime.value = d.toLocaleString();
}
let timer: any = null;

// 数字滚动动画
function animateNumber(refNum: any, target: number, duration = 1200) {
  const start = refNum.value;
  const diff = target - start;
  if (diff === 0) return;
  const startTime = performance.now();
  function step(now: number) {
    const progress = Math.min((now - startTime) / duration, 1);
    refNum.value = Math.floor(start + diff * progress);
    if (progress < 1) {
      requestAnimationFrame(step);
    } else {
      refNum.value = target;
    }
  }
  requestAnimationFrame(step);
}

// 固定星星参数，避免闪烁
const STAR_NUM = 16;
const starsParams = Array.from({ length: STAR_NUM }).map(() => {
  const posType = Math.floor(Math.random() * 4);
  let style: any = {};
  if (posType === 0) style = { top: Math.random() * 60 + 'px', left: Math.random() * 100 + 'vw' };
  if (posType === 1) style = { bottom: Math.random() * 60 + 'px', left: Math.random() * 100 + 'vw' };
  if (posType === 2) style = { left: Math.random() * 60 + 'px', top: Math.random() * 100 + 'vh' };
  if (posType === 3) style = { right: Math.random() * 60 + 'px', top: Math.random() * 100 + 'vh' };
  const size = Math.random() * 2 + 1.5;
  return {
    ...style,
    width: size + 'px',
    height: size + 'px',
    animationDelay: (Math.random() * 2) + 's',
    '--star-move': (Math.random() * 12 + 8) + 'px',
    '--star-scale': (Math.random() * 0.5 + 0.8)
  };
});
function starStyle(n: number) {
  return starsParams[n - 1];
}

// 动态数据定时变化
let dataTimer: any = null;
function randomDelta(val: number, range: number) {
  return val + Math.round((Math.random() - 0.5) * range);
}
function updateDynamicData() {
  // 今日访问量、活跃用户、营收、设备数大幅波动
  todayVisits.value = randomDelta(todayVisits.value, 300) + Math.floor(Math.random() * 50);
  activeUsers.value = randomDelta(activeUsers.value, 100) + Math.floor(Math.random() * 20);
  monthIncome.value = randomDelta(monthIncome.value, 20000) + Math.floor(Math.random() * 1000);
  onlineDevices.value = randomDelta(onlineDevices.value, 10) + Math.floor(Math.random() * 3);
  // 活跃率、设备率波动
  activeRate.value = Math.max(0.5, Math.min(0.98, activeRate.value + (Math.random() - 0.5) * 0.05));
  deviceRate.value = Math.max(0.6, Math.min(0.99, deviceRate.value + (Math.random() - 0.5) * 0.03));
  // 地区分布、订单趋势动态变化
  regionData.value = regionData.value.map(item => ({
    ...item,
    value: Math.max(10, Math.min(100, item.value + Math.round((Math.random() - 0.5) * 18)))
  }));
  orderTrend.value = orderTrend.value.map(item => ({
    ...item,
    value: Math.max(10, Math.min(100, item.value + Math.round((Math.random() - 0.5) * 20)))
  }));
  // 地图数据同步大幅波动
  mapData[0].value = Math.max(100, Math.min(500, mapData[0].value + Math.round((Math.random() - 0.5) * 80)));
  mapData[1].value = Math.max(100, Math.min(600, mapData[1].value + Math.round((Math.random() - 0.5) * 120)));
  mapData[2].value = Math.max(400, Math.min(1000, mapData[2].value + Math.round((Math.random() - 0.5) * 180)));
  mapData[3].value = Math.max(200, Math.min(800, mapData[3].value + Math.round((Math.random() - 0.5) * 100)));
  if (myChart) {
    myChart.setOption({
      series: [{ data: mapData }]
    });
  }
}

onMounted(async () => {
  await nextTick();
  setScale();
  window.addEventListener('resize', setScale);
  timer = setInterval(updateTime, 1000);
  dataTimer = setInterval(updateDynamicData, 2000);
  updateTime();
  // 数字动画
  animateNumber(todayVisits, todayVisitsTarget);
  animateNumber(activeUsers, activeUsersTarget);
  animateNumber(monthIncome, monthIncomeTarget);
  animateNumber(onlineDevices, onlineDevicesTarget);
  if (mapRef.value) {
    echarts.registerMap('china', chinaMap as any);
    myChart = echarts.init(mapRef.value);
    let visualMin = 0;
    let visualMax = 1000;
    myChart.setOption({
      tooltip: { trigger: 'item' },
      visualMap: {
        min: visualMin,
        max: visualMax,
        left: 'left',
        bottom: 30,
        text: ['高', '低'],
        inRange: { color: ['#00eaff', '#2979ff', '#ff6b81', '#ffd600'] },
        show: true,
        realtime: true,
        calculable: true
      },
      series: [
        {
          name: '数据',
          type: 'map',
          map: 'china',
          roam: true,
          label: { show: true, color: '#fff', fontWeight: 'bold' },
          itemStyle: {
            areaColor: '#12223a',
            borderColor: '#00eaff',
            borderWidth: 1.5,
            shadowColor: '#2979ff',
            shadowBlur: 10
          },
          emphasis: {
            label: { color: '#ffd600' },
            itemStyle: { areaColor: '#2979ff' }
          },
          data: mapData
        }
      ]
    });
    window.addEventListener('resize', resizeChart);
    // 联动visualMap滑块
    myChart.on('visualmap:changed', function (params: any) {
      // params为{type, visualMapIndex, option, target, range}
      // 只高亮当前范围内的省份
      const [min, max] = params.range;
      myChart.setOption({
        series: [{
          data: mapData.map(item => ({
            ...item,
            itemStyle: (item.value >= min && item.value <= max)
              ? { areaColor: '#ffd600', borderColor: '#ff6b81', borderWidth: 2 }
              : undefined
          }))
        }]
      });
    });
  }
});

onUnmounted(() => {
  window.removeEventListener('resize', setScale);
  window.removeEventListener('resize', resizeChart);
  if (timer) clearInterval(timer);
  if (dataTimer) clearInterval(dataTimer);
  if (myChart) {
    myChart.dispose();
    myChart = null;
  }
});
</script>

<style scoped>
.large-screen-bg {
  min-height: 100vh;
  width: 100vw;
  /* 现代科技感深蓝紫渐变背景 */
  background: linear-gradient(120deg, #181c2f 0%, #232a4d 40%, #1a2a3a 100%),
    radial-gradient(ellipse at 70% 30%, #2e4cff 0%, transparent 60%),
    radial-gradient(ellipse at 20% 80%, #00eaff 0%, transparent 70%);
  background-blend-mode: lighten, screen;
  position: relative;
  overflow: hidden;
}
.bg-animate {
  pointer-events: none;
  position: fixed;
  left: 0; top: 0; width: 100vw; height: 100vh;
  z-index: 0;
}
/* 动感光斑 */
.bg-animate::before, .bg-animate::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  opacity: 0.18;
  pointer-events: none;
  z-index: 0;
}
.bg-animate::before {
  width: 420px; height: 420px;
  left: 8vw; top: 10vh;
  background: radial-gradient(circle, #00eaff 0%, #232a4d 80%);
  animation: bgDotMove1 8s linear infinite alternate;
}
.bg-animate::after {
  width: 320px; height: 320px;
  right: 10vw; bottom: 12vh;
  background: radial-gradient(circle, #2e4cff 0%, #232a4d 80%);
  animation: bgDotMove2 10s linear infinite alternate;
}
@keyframes bgDotMove1 {
  0% { left: 8vw; top: 10vh; opacity: 0.16; }
  100% { left: 14vw; top: 16vh; opacity: 0.28; }
}
@keyframes bgDotMove2 {
  0% { right: 10vw; bottom: 12vh; opacity: 0.16; }
  100% { right: 16vw; bottom: 18vh; opacity: 0.28; }
}
.glow-top, .glow-bottom, .glow-left, .glow-right {
  position: absolute;
  pointer-events: none;
  z-index: 1;
  opacity: 0.7;
}
.glow-top {
  top: 0; left: 0; width: 100vw; height: 32px;
  background: linear-gradient(90deg, #00eaff 0%, #ffd600 100%);
  filter: blur(10px);
  animation: glowMoveX 3.5s linear infinite alternate;
}
.glow-bottom {
  bottom: 0; left: 0; width: 100vw; height: 32px;
  background: linear-gradient(90deg, #ff6b81 0%, #2979ff 100%);
  filter: blur(10px);
  animation: glowMoveX 4s linear infinite alternate-reverse;
}
.glow-left {
  top: 0; left: 0; width: 32px; height: 100vh;
  background: linear-gradient(180deg, #ffd600 0%, #00eaff 100%);
  filter: blur(10px);
  animation: glowMoveY 3.2s linear infinite alternate;
}
.glow-right {
  top: 0; right: 0; width: 32px; height: 100vh;
  background: linear-gradient(180deg, #2979ff 0%, #ff6b81 100%);
  filter: blur(10px);
  animation: glowMoveY 4.2s linear infinite alternate-reverse;
}
@keyframes glowMoveX {
  0% { transform: translateX(0); }
  100% { transform: translateX(24px); }
}
@keyframes glowMoveY {
  0% { transform: translateY(0); }
  100% { transform: translateY(24px); }
}
.stars {
  position: absolute;
  left: 0; top: 0; width: 100vw; height: 100vh;
  z-index: 2;
  pointer-events: none;
}
.star {
  position: absolute;
  background: #fff;
  border-radius: 50%;
  opacity: 0.7;
  box-shadow: 0 0 8px #ffd600, 0 0 16px #00eaff;
  animation: starFloat 2.2s infinite alternate;
  will-change: transform, opacity;
  transform: scale(var(--star-scale,1)) translateY(0);
}
@keyframes starFloat {
  0% { opacity: 0.7; transform: scale(var(--star-scale,1)) translateY(0); }
  100% { opacity: 1; transform: scale(var(--star-scale,1)) translateY(var(--star-move,12px)); }
}
.scale-wrapper {
  z-index: 10;
}
.scale-wrapper {
  width: 1920px;
  height: 1080px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: scale(1) translate(-50%, -50%);
  transform-origin: left top;
  z-index: 1;
}
.large-screen-container {
  display: flex;
  height: 100%;
  width: 100%;
  box-sizing: border-box;
  justify-content: center;
  align-items: center;
}
.side-panel {
  width: 340px;
  min-width: 180px;
  max-width: 400px;
  background: rgba(24, 48, 72, 0.92);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 32px 12px 32px 12px;
  box-sizing: border-box;
  border-radius: 18px;
  box-shadow: 0 0 32px #0a1a2a99, 0 0 0 2px #3a7bd5 inset;
  margin: 0 18px;
  border: 1.5px solid #3a7bd5;
  position: relative;
}
.left-panel {
  border-right: 2px solid #3a7bd5;
}
.right-panel {
  border-left: 2px solid #3a7bd5;
}
.panel-title {
  color: #3a7bd5;
  font-size: 1.4rem;
  font-weight: bold;
  letter-spacing: 2px;
  margin-bottom: 28px;
  text-shadow: 0 2px 8px #3a7bd5aa;
}
.center-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  position: relative;
}
.main-title {
  color: #fff;
  font-size: 2.2rem;
  font-weight: bold;
  letter-spacing: 4px;
  margin-bottom: 8px;
  text-shadow: 0 4px 24px #3a7bd5cc, 0 1px 0 #222;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.main-title .logo {
  width: 48px;
  height: 48px;
  margin-bottom: 8px;
  border-radius: 50%;
  box-shadow: 0 0 12px #ffd600;
}
.subtitle {
  color: #ffd600;
  font-size: 1.1rem;
  margin-top: 2px;
  margin-bottom: 2px;
  letter-spacing: 2px;
  text-shadow: 0 2px 8px #ffd60099;
}
.time {
  color: #00eaff;
  font-size: 1.1rem;
  margin-top: 2px;
  letter-spacing: 2px;
  text-shadow: 0 2px 8px #00eaff99;
}
.map-container {
  width: 1200px;
  height: 800px;
  background: linear-gradient(120deg, #12223a 60%, #1e3c72 100%);
  border-radius: 22px;
  box-shadow: 0 0 48px #3a7bd5cc, 0 0 0 3px #3a7bd5 inset;
  border: 2px solid #3a7bd5;
  position: relative;
  overflow: hidden;
}
.data-card {
  width: 94%;
  background: linear-gradient(100deg, #18324a 60%, #3a7bd5 100%);
  color: #fff;
  margin: 18px 0;
  padding: 22px 14px;
  border-radius: 12px;
  box-shadow: 0 4px 16px #3a7bd5aa, 0 0 0 2px #3a7bd5 inset;
  text-align: center;
  border: 1.5px solid #3a7bd5;
  transition: transform 0.2s, box-shadow 0.2s;
  position: relative;
}
.highlight-card {
  background: linear-gradient(100deg, #ff6b81 60%, #ffd600 100%);
  color: #222;
  border: 1.5px solid #ffd600;
  box-shadow: 0 4px 24px #ffd60099, 0 0 0 2px #ff6b81 inset;
}
.card-label {
  font-size: 1.1rem;
  font-weight: bold;
  margin-bottom: 6px;
  color: #fff;
  text-shadow: 0 2px 8px #3a7bd599;
}
.card-value {
  font-size: 2.1rem;
  font-weight: bold;
  color: #ffd600;
  text-shadow: 0 2px 8px #fff4;
  margin-bottom: 4px;
}
.card-sub {
  font-size: 1rem;
  color: #00eaff;
  margin-top: 2px;
}
.card-sub .up {
  color: #ff1744;
  font-weight: bold;
}
.progress-ring {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 8px auto 0 auto;
  position: relative;
}
.progress-ring svg {
  display: block;
}
.progress-text {
  position: absolute;
  left: 0; right: 0; top: 18px;
  text-align: center;
  width: 60px;
  color: #ffd600;
  font-size: 1.1rem;
  font-weight: bold;
  text-shadow: 0 2px 8px #ffd60099;
}
.mini-bar {
  width: 100%;
  margin-top: 8px;
}
.mini-bar-item {
  display: flex;
  align-items: center;
  margin-bottom: 4px;
}
.mini-bar-label {
  width: 48px;
  font-size: 0.95rem;
  color: #00eaff;
  margin-right: 6px;
}
.mini-bar-bar {
  height: 12px;
  border-radius: 6px;
  margin-right: 6px;
  transition: width 0.6s;
  min-width: 8px;
}
.mini-bar-value {
  font-size: 0.95rem;
  color: #ffd600;
  min-width: 24px;
}

/* 动画效果增强 */
.data-card, .highlight-card {
  animation: cardFadeIn 0.8s cubic-bezier(.4,2,.6,1) both;
}
@keyframes cardFadeIn {
  0% { opacity: 0; transform: translateY(40px) scale(0.95); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
.progress-ring svg circle:last-child {
  filter: drop-shadow(0 0 8px #ffd600) drop-shadow(0 0 16px #00eaff);
  animation: ringPulse 1.8s infinite alternate;
}
@keyframes ringPulse {
  0% { filter: drop-shadow(0 0 8px #ffd600) drop-shadow(0 0 16px #00eaff); }
  100% { filter: drop-shadow(0 0 24px #ffd600) drop-shadow(0 0 32px #00eaff); }
}
.main-title {
  animation: titleGlow 2.5s infinite alternate;
}
@keyframes titleGlow {
  0% { text-shadow: 0 4px 24px #3a7bd5cc, 0 1px 0 #222; }
  100% { text-shadow: 0 8px 48px #ffd600cc, 0 1px 0 #222; }
}
.time {
  animation: timeFade 1.5s infinite alternate;
}
@keyframes timeFade {
  0% { color: #00eaff; }
  100% { color: #ffd600; }
}

/* 响应式适配 */
@media (max-width: 1200px) {
  .large-screen-container {
    flex-direction: column;
    height: auto;
    min-height: 100vh;
    align-items: stretch;
  }
  .side-panel {
    width: 96vw;
    min-width: 0;
    max-width: none;
    margin: 18px auto;
    flex-direction: row;
    justify-content: center;
    padding: 12px 0;
  }
  .center-panel {
    min-width: 0;
    margin: 0 auto;
  }
  .map-container {
    width: 92vw;
    height: 60vw;
    min-width: 200px;
    min-height: 180px;
    max-width: 98vw;
    max-height: 60vh;
  }
}
@media (max-width: 700px) {
  .large-screen-bg {
    padding: 0;
  }
  .large-screen-container {
    flex-direction: column;
    height: auto;
    min-height: 100vh;
    align-items: stretch;
  }
  .side-panel {
    width: 98vw;
    min-width: 0;
    max-width: none;
    margin: 10px auto;
    flex-direction: column;
    align-items: center;
    padding: 8px 0;
  }
  .center-panel {
    min-width: 0;
    margin: 0 auto;
  }
  .main-title {
    font-size: 1.1rem;
    margin-bottom: 8px;
  }
  .map-container {
    width: 98vw;
    height: 60vw;
    min-width: 120px;
    min-height: 100px;
    max-width: 99vw;
    max-height: 40vh;
  }
  .data-card {
    font-size: 0.85rem;
    padding: 8px 4px;
  }
}
</style>